-- =========================================================================================
-- 				PROTECT THE VIP - Gamemode by SteveUK
--  You are free to make modifications and redistributions of this gamemode as long as I'm credited for it
--=========================================================================================

-- THESE WEAPONS WILL ONLY WORK WITH THIS GAMEMODE DUE TO ADDITIONS TO THE PLAYER META TABLE
-- define everything plz.
SWEP.Settings 				= {}
SWEP.Stance 				= {}

SWEP.Base					= "weapon_base" -- use the base weapon as a base durrr
SWEP.Author					= "SteveUK"
SWEP.Contact				= "stephen.swires@gmail.com"
SWEP.Purpose				= "Protect the VIP SWEP"
SWEP.Instructions			= "Left mouse to shoot"

SWEP.ViewModelFOV			= 64
SWEP.ViewModelFlip			= true
SWEP.ViewModel				= "models/weapons/v_pist_deagle.mdl"
SWEP.WorldModel				= "models/weapons/w_pist_deagle.mdl"

SWEP.Settings.OldRunSpeed	= 0 -- placeholder, if it's 0 it won't set it back to the original
SWEP.Settings.OldWalkSpeed	= 0 -- as above, with walking
SWEP.Settings.RunSpeed		= 300 -- run speed from the hip
SWEP.Settings.WalkSpeed		= 250
SWEP.Settings.IronRunSpeed	= 200 -- ironsighted run speed
SWEP.Settings.IronWalkSpeed	= 150

SWEP.Settings.IronCvar		= true
SWEP.Settings.IronPos		= Vector( 5.15, -2, 2.6 ) -- ironsights
SWEP.Settings.IronAng		= Angle( 0, 0, 0 )
SWEP.Settings.IronTime		= 0.25

SWEP.Settings.WillDrop		= true

SWEP.Primary.ClipSize		= 7
SWEP.Primary.DefaultClip	= 27
SWEP.Primary.ShotBullets	= 1 -- how many bullets are in a single attack? hello shotgun
SWEP.Primary.Damage			= 50
SWEP.Primary.RateOfFire		= 0.2
SWEP.Primary.Recoil			= 2.13
SWEP.Primary.Spread			= 0.025 -- aka cone
SWEP.Primary.Automatic		= false
SWEP.Primary.Ammo			= "Pistol" -- in SWEPs we'll use pistol for sec, smg for pri
SWEP.Primary.ShootSound		= "Weapon_Deagle.Single"
SWEP.Primary.EmptySound		= "Weapon_Deagle.Empty"
SWEP.Primary.NextAttack		= 0
SWEP.Primary.Tracers		= 4

SWEP.Secondary.ClipSize		= -1
SWEP.Secondary.DefaultClip	= -1
SWEP.Secondary.RateOfFire	= 1.0 
SWEP.Secondary.Automatic	= true
SWEP.Secondary.Ammo			= "none"
SWEP.Secondary.NextAttack	= 0

SWEP.Stance.CrouchRecoil 	= 0.65 -- these are multipliers btw, these are compared to standing still
SWEP.Stance.WalkingRecoil	= 1.05
SWEP.Stance.SprintRecoil	= 1.25
SWEP.Stance.JumpRecoil		= 1.8
SWEP.Stance.JCRecoil 		= 1.5 -- crouch jumping
SWEP.Stance.CrouchSpread	= 0.7
SWEP.Stance.WalkingSpread	= 1.1
SWEP.Stance.SprintSpread	= 1.37
SWEP.Stance.JumpSpread		= 1.95
SWEP.Stance.JCSpread		= 1.75
SWEP.Stance.CrouchDamage	= 1.1
SWEP.Stance.WalkingDamage	= 1.0
SWEP.Stance.SprintDamage	= 1.0
SWEP.Stance.JumpDamage		= 0.95
SWEP.Stance.JCDamage		= 1.0
SWEP.Stance.IronsightMulti	= 0.8 -- a further multiplier for when the ironsights are enabled (recoil & spread only)

-- when the swep is initialized. we don't have anything yet.
function SWEP:Initialize()

	if( !SERVER ) then return end
	self:SetWeaponHoldType( self.HoldType ) -- hold it properly
	self.Weapon:SetNetworkedBool( "Ironsights", false ) -- disable ironsights initially.
	
end

-- precache our models, that's a good idea!
function SWEP:Precache()
	util.PrecacheModel( self.ViewModel ) -- vm
	util.PrecacheModel( self.WorldModel ) -- wm
end

-- +attack plx
function SWEP:PrimaryAttack()

	if( !self:CanPrimaryAttack() ) then return end
	self:ShootBullet( self.Primary.Damage, self.Primary.ShotBullets, self.Primary.Spread )
	self.Primary.NextAttack = CurTime() + self.Primary.RateOfFire -- We can easily override the engine's next attack features with this

end

-- Ironsights or scope probs
function SWEP:SecondaryAttack()

	if( !self.Settings.IronPos ) then return end
	if( !self:CanSecondaryAttack() ) then return end
	
	bIronsights = !self.Weapon:GetNetworkedBool( "Ironsights", false )
	self:SetIronsights( bIronsights )
	self.Secondary.NextAttack = CurTime() + self.Secondary.RateOfFire
	Msg( "Ironsights: " .. tostring( bIronsights ) .. "\n" )
	
end

-- reload this probably won't change unless you want it to do something special
function SWEP:Reload()
	self:SetIronsights( false ) -- disable is
	self.Weapon:DefaultReload( ACT_VM_RELOAD ) -- reload as normal
end

-- Ima thinkin'
function SWEP:Think()
end

-- Holster
function SWEP:Holster( wep )
	
	if( SERVER ) then
		if( self.Weapon.OldRunSpeed != 0 and self.Weapon.OldWalkSpeed != 0 ) then
			GAMEMODE:SetPlayerSpeed( self.Owner, self.Settings.OldWalkSpeed, self.Settings.OldRunSpeed ) -- restore old walking speed
		end
	end
	
	self:SetIronsights( false )
	return true
	
end

-- Deploy
function SWEP:Deploy()

	-- running speed shit now
	self.Settings.OldRunSpeed = self.Owner:GetTable().SprintSpeed -- store old speed
	self.Settings.OldWalkSpeed = self.Owner:GetTable().WalkSpeed -- store old speed
	
	-- set our run and walk speed
	GAMEMODE:SetPlayerSpeed( self.Owner, self.Settings.WalkSpeed, self.Settings.RunSpeed )
	
	-- reset irons
	self:SetIronsights( false )
	
	return true
end

-- All this jibba jobba, might rewrite it because of the pecker muzzle flash
function SWEP:ShootEffects()

	self.Weapon:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
	self.Owner:MuzzleFlash()
	self.Owner:SetAnimation( PLAYER_ATTACK1 )

end

-- Shoot bullets plz
function SWEP:ShootBullet( damage, num_bullets, aimcone )
	
	local recoilangs = self.Primary.Recoil
	
	-- stance modifiers
	if( self.Owner:CrouchJumping() == true ) then
		recoilangs = recoilangs * self.Stance.JCRecoil
		aimcone = aimcone * self.Stance.JCSpread
		damage = damage * self.Stance.JCDamage
	elseif( self.Owner:IsOnGround() == false ) then
		recoilangs = recoilangs * self.Stance.JumpRecoil
		aimcone = aimcone * self.Stance.JumpSpread
		damage = damage * self.Stance.JumpDamage		
	elseif( self.Owner:Crouching() == true ) then
		recoilangs = recoilangs * self.Stance.CrouchRecoil
		aimcone = aimcone * self.Stance.CrouchSpread
		damage = damage * self.Stance.CrouchDamage	
	elseif( self.Owner:Walking() == true ) then
		recoilangs = recoilangs * self.Stance.WalkingRecoil
		aimcone = aimcone * self.Stance.WalkingSpread
		damage = damage * self.Stance.WalkingDamage
	elseif( self.Owner:Running() == true ) then
		recoilangs = recoilangs * self.Stance.RunningRecoil
		aimcone = aimcone * self.Stance.RunningSpread
		damage = damage * self.Stance.RunningDamage
	end
	
	-- ironsight modifiers
	if( self.Weapon:GetNetworkedBool( "Ironsights", false ) == true ) then
		recoilangs = recoilangs * self.Stance.IronsightMulti
		aimcone = aimcone * self.Stance.IronsightMulti
	end
	
	local bullet 	= {}
	bullet.Num 		= num_bullets
	bullet.Src 		= self.Owner:GetShootPos()
	bullet.Dir 		= self.Owner:GetAimVector()
	bullet.Spread 	= Vector( aimcone, aimcone, 0 )
	bullet.Tracer	= self.Primary.Tracers
	bullet.Force	= ( self.Primary.Damage / 2 )
	bullet.Damage	= damage
	bullet.AmmoType = self.Primary.Ammo
	
	self.Weapon:EmitSound( self.Primary.ShootSound ) -- sound
	self.Owner:FireBullets( bullet ) -- bullet
	self:TakePrimaryAmmo( 1 ) -- ammo
	self:ShootEffects() -- effects
	self.Owner:ViewPunch( Angle( math.Rand(-0.2,-0.1) * recoilangs, math.Rand(-0.1,0.1) * recoilangs, 0 ) ) -- recoil

	if ( (SinglePlayer() && SERVER) || ( !SinglePlayer() && CLIENT ) ) then
		local eyeang = self.Owner:EyeAngles()
		eyeang.pitch = eyeang.pitch - recoilangs
		self.Owner:SetEyeAngles( eyeang )
	end	
	
end

-- change a little
function SWEP:CanPrimaryAttack()

	if( self.Primary.NextAttack <= CurTime() ) then
		return true
	elseif( self.Weapon:Clip1() <= 0 ) then
		self.Weapon:EmitSound( self.Primary.EmptySound )
		self.Weapon:SetNextPrimaryFire( CurTime() + 0.2 )
		return false	
	end

	return true

end

-- removed pistol empty sound here
function SWEP:CanSecondaryAttack()
	
	if( self.Secondary.NextAttack <= CurTime() ) then
		return true
	elseif( self.Weapon:Clip2() <= 0 ) then
		self.Weapon:SetNextSecondaryFire( CurTime() + 0.2 )
		return false
	end

	return true

end

-- Dropping here amirite?
function SWEP:OnRemove()

	if( self.Owner:Alive() == false and self.Settings.WillDrop == true ) then
		newent = ents.Create( self.Weapon:GetClass() )
		newent:SetPos( self.Weapon:GetPos() )
		newent:SetAngs( self.Weapon:GetAngs() )
		newent:Spawn()
		newent:Activate()
	end
	
end

-- Give them some ammo? dunno.
function SWEP:OwnerChanged()
end

-- Helper function for setting the ironsight setting
function SWEP:SetIronsights( b )

	if( b == false ) then -- FOV setting and run speed
		self.Owner:SetFOV( 0, 0.3 )
		GAMEMODE:SetPlayerSpeed( self.Owner, self.Settings.WalkSpeed, self.Settings.RunSpeed )
	else
		self.Owner:SetFOV( 45, 0.3 )
		GAMEMODE:SetPlayerSpeed( self.Owner, self.Settings.IronWalkSpeed, self.Settings.IronRunSpeed )
	end
	
	self.Weapon:SetNetworkedBool( "Ironsights", b )
end

-- sort our ironsights out, most is garry's code
function SWEP:GetViewModelPosition( pos, ang )

	if( !self.Settings.IronPos ) then return end
	Msg( "Drawing ironsight..or not. We got an IRONPOS\n" )
	
	local bIron = self.Weapon:GetNetworkedBool( "Ironsights", false )
	
	if ( bIron != self.bLastIron ) then
		self.bLastIron = bIron 
		self.fIronTime = CurTime()
		
		if ( bIron ) then 
			self.SwayScale 	= 0.2
			self.BobScale 	= 0.05
		else 
			self.SwayScale 	= 1.0
			self.BobScale 	= 1.0
		end
	end
	
	local fIronTime = self.fIronTime or 0

	if ( !bIron && fIronTime < CurTime() - self.Settings.IronTime ) then 
		Msg( "!bIron && fIronTime < CurTime() - self.Settings.IronTime\n" )
		return pos, ang 
	end
	
	local Mul = 1.0
	
	if ( fIronTime > CurTime() - self.Settings.IronTime ) then
		Mul = math.Clamp( (CurTime() - fIronTime) / (self.Settings.IronTime or 0.25), 0, 1 )
		if (!bIron) then Mul = 1 - Mul end
	end

	local Offset	= self.Settings.IronPos
	
	if ( self.Settings.IronAng ) then
		ang = ang * 1
		ang:RotateAroundAxis( ang:Right(), 		self.Settings.IronAng.x * Mul )
		ang:RotateAroundAxis( ang:Up(), 		self.Settings.IronAng.y * Mul )
		ang:RotateAroundAxis( ang:Forward(), 	self.Settings.IronAng.z * Mul )
	end
	
	local Right 	= ang:Right()
	local Up 		= ang:Up()
	local Forward 	= ang:Forward()
	
	pos = pos + Offset.x * Right * Mul
	pos = pos + Offset.y * Forward * Mul
	pos = pos + Offset.z * Up * Mul

	return pos, ang
	
end
